package org.acghub.config.exchanger;

import lombok.extern.slf4j.Slf4j;
import org.acghub.config.*;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.Optional;

/**
 * @Desc
 * @Author miyuki4j
 * @Date 2025/7/25/星期五 18:33
 * @Version 1.0
 */
@Slf4j
public class XmlTableDataExchanger implements TableDataExchanger {
    @Override
    public TableDataExchangerEnum type() {
        return TableDataExchangerEnum.XML;
    }

    @Override
    public void exportData(String exportDir, TableData tableData) throws TableDataExportException {

        final TableMeta meta = tableData.getMeta();
        final String fileName = type().concatFileName(meta.getClassName());
        final File exportFile = new File(exportDir, fileName);
        if (exportFile.exists()) {
            exportFile.delete();
        }

        // 设置输出格式（缩进、编码）
        final String encoding = TableConfig.get(TableConfig.ConfigKeyEnum.ENCODING, "UTF-8");
        final Charset charset = Charset.forName(encoding);
        final OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding(encoding);

        // 转为 Document
        final Document xmlDocument = toXmlDocument(tableData);

        // 开始导出
        try (XMLWriter writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream(exportFile), charset), format)) {
            writer.write(xmlDocument);
            writer.flush();
        } catch (Exception e) {
            throw new TableDataExportException("导出文件失败, fileName：" + fileName, e);
        }
        log.debug("导出文件成功, fileName：{}", fileName);
    }

    private Document toXmlDocument(TableData tableData) {
        Document document = DocumentHelper.createDocument();
        TableMeta meta = tableData.getMeta();
        String className = meta.getClassName();
        Element root = document.addElement(className);

        // row
        for (TableDataRow tableDataRow : tableData) {
            Element rowElement = root.addElement("entity");
            // cell
            for (TableDataCell tableDataCell : tableDataRow) {
                Optional<TableField> tableFieldOptional = meta.getHeader().get(tableDataCell.getColumn());
                if (tableFieldOptional.isEmpty()) {
                    continue;
                }
                TableField tableField = tableFieldOptional.get();
                rowElement.addElement(tableField.getName()).setText(tableDataCell.getExportValue());
            }
        }
        return document;
    }

    /**
     * xml 文件转成 ImportData
     */
    @Override
    public ImportData importData(File file) throws TableDataImportException {
        try {
            SAXReader saxReader = SAXReader.createDefault();
            saxReader.setEncoding(TableConfig.get(TableConfig.ConfigKeyEnum.ENCODING, "UTF-8"));
            Document document = saxReader.read(file);
            String className = type().cutClassName(file.getName());
            return toImportData(className, document);
        } catch (Exception e) {
            throw new TableDataImportException("导入文件失败, fileName：" + file.getName(), e);
        }
    }

    private ImportData toImportData(String className, Document document) {
        ImportData importData = new ImportData(className);
        int rowIndex = 1;
        for (Element rowElement : document.getRootElement().elements("entity")) {
            TableDataRow tableDataRow = new TableDataRow(rowIndex++);
            for (Element cellelement : rowElement.elements()) {
                TableDataCell tableDataCell = new TableDataCell(cellelement.getName(), cellelement.getText());
                tableDataRow.add(tableDataCell);
            }
            importData.add(tableDataRow);
        }
        return importData;
    }

}
